#include "algorithm-test.h"
#include "string-util.h"
#include <algorithm>
#include <iterator>
#include <iostream>
#include <string>
#include <map>
#include <exception>
#include <stdexcept>
using namespace std;
ELAlgorithmTest* ELAlgorithmTest::runTest()
{
	//testCountIf();
	//testMax();
	//testVector();
	testMap();
	//testString();
	//testMapErase();
	clearItems();
	clearMapOfList();
	return this;
}

ELAlgorithmTest::ELAlgorithmTest()
{
	mItems.clear();
	pln("ELAlgorithmTest()");
}

ELAlgorithmTest::~ELAlgorithmTest()
{
	pln("~ELAlgorithmTest()");
}

bool ELAlgorithmTest::testCountIf() const
{
	int ary[] = {1, 2, 3, 4, 1, 3, 4, 5, 2, 1, 2, 3, 4, 5, 10};

	// create target.
	vector<int> target(ary, ary+sizeof ary / sizeof ary[0]);
	sort(target.begin(), target.end());
	vector<int>::iterator iter = unique(target.begin(), target.end());
	target.resize(std::distance(target.begin(), iter));    // target: {1, 2, 3, 4, 5, 10}
	pln("target");
	copy(target.begin(), target.end(), ostream_iterator<int>(cout , ","));
	cr;

	// create src
	vector<int> ivec(sizeof ary / sizeof ary[0]);
	copy(ary, ary+sizeof ary / sizeof ary[0], ivec.begin());    // src: = ary
	pln("src");
	copy(ivec.begin(), ivec.end(), ostream_iterator<int>(cout, ","));
	cr;

	// sum each  kind ids
	//
	vector<int>::iterator it = target.begin();
	while (it != target.end()) {
		int stoneId = *it;
		p(*it); p(" : "); 
		// todo: check this in vs2013
		//p(count_if(ivec.begin(), ivec.end(), bind1st(equal_to<int>(), stoneId)));
		cr;
		++it;
	}
	return true;
}

bool ELAlgorithmTest::testMax() const {
	int maxa = std::max(10, 100);
	pln(maxa);
	return true;
}

bool ELAlgorithmTest::testVector()
{
	int len = 10;
	for (int i=0; i<len; ++i) {
		mItems.push_back(new Item(i, i*10));
	}
	return true;
}

bool ELAlgorithmTest::clearItems()
{
	ItemList::iterator it = mItems.begin();
	while (it != mItems.end()) {
		delete (*it);
		++it;
	}
	mItems.clear();
	return false;
}

bool ELAlgorithmTest::testMap()
{
	/*
	map<int, int*> aMap;
	int * p = aMap[0];
	if (!p) {
		pln("p is null");
	}
	else {
		pln("oh, i get a valid ptr from an empty map");
	}
	*/

	// test vector's map
	for (int i=0; i<10; ++i) {
		unsigned int id = rand() % 10;
		if (mItemListsMap.find(id) != mItemListsMap.end()) {
			removeItemWithId(id);
		}
		addItemsToMapOfList(id, id+i, id+i);
	}

	ItemListMap::iterator it = mItemListsMap.begin();
	while (it != mItemListsMap.end()) {
		psln("show-------------------------------------");
		int id = it->first;
		ItemList temp = it->second;
		psln(id);
		for (int j=0; j<temp.size(); ++j) {
			psln(j);
			psln(temp[j]->mId);
			psln(temp[j]->mCount);
		}
		++it;
	}
	
	return true;
}

void ELAlgorithmTest::addItemsToMapOfList(unsigned int listId, int id, int count)
{
	
	ItemListMap::iterator it = mItemListsMap.find(listId);
	if ( it != mItemListsMap.end()) {
		it->second.push_back(new Item(id, count));
	}
	else {
		ItemList temp;
		temp.push_back(new Item(id, count));
		mItemListsMap[listId] = temp;
	}
}

void ELAlgorithmTest::clearMapOfList()
{
	ItemListMap::iterator it = mItemListsMap.begin();
	while (it != mItemListsMap.end()) {
		psln("clear map");
		int id = it->first;
		ItemList temp = it->second;
		psln(id);
		for (int j=0; j<temp.size(); ++j) {
			psln("clear list j");
			psln(j);
			if (temp[j]) {
				delete temp[j];
				temp[j]  = 0;
			}
		}
		++it;
	}
}

void walk(string& animal) {
	// dog, fish, bird
	if (animal == "dog") {
		ps("walk");
	}
	else if (animal == "duck") {
		psln("swim");
	}
	else if (animal == "bird") {
		psln("fly");
	}
}

bool ELAlgorithmTest::testString()
{
	//string test("hello");
	//size_t pos = test.find_last_of('d');
	////try {
	//	if (pos == string::npos) {
	//		string sub = test.substr(pos+100, 100);
	//		p(sub);
	//		p("-end");
	//	}
	////}
	///*catch (const std::out_of_range& oor ) {
	//	psln(oor.what());
	//}*/
	//

	string animal("dog");
	walk(animal);
	return true;
}

void ELAlgorithmTest::testMapErase()
{
	typedef map<unsigned int, vector<Item*> > MapOfList;
	MapOfList mMap;
	vector<Item*> tmp;
	tmp.push_back(new Item(1, 1));
	tmp.push_back(new Item(2, 2));
	mMap[0] = tmp;

	psln("after insert 0");

	MapOfList::iterator iter = mMap.begin();
	while (iter != mMap.end()) {
		psln("======================item===============");
		psln(iter->first);
		for (size_t i=0; i<iter->second.size(); ++i) {
			psln(iter->second[i]->mId);
			psln(iter->second[i]->mCount);
		}
		++iter;
	}

	tmp.clear();
	tmp.push_back(new Item(3,3));
	tmp.push_back(new Item(4,4));
	mMap[1] = tmp;

	psln("after insert 1");

	iter = mMap.begin();
	while (iter != mMap.end()) {
		psln("======================item===============");
		psln(iter->first);
		for (size_t i=0; i<iter->second.size(); ++i) {
			psln(iter->second[i]->mId);
			psln(iter->second[i]->mCount);
		}
		++iter;
	}

	iter = mMap.find(0);
	if (iter != mMap.end()) {
		psln("erase item");
		psln(iter->first);
		for (size_t i=0; i<iter->second.size(); ++i) {
			delete iter->second[i];
			iter->second[i] = 0;
		}
		iter->second.clear();
		vector<Item*> temp;
		iter->second.swap(temp);
		mMap.erase(iter);
	}

	
	psln("after delete 0");

	iter = mMap.begin();
	while (iter != mMap.end()) {
		psln("======================item===============");
		psln(iter->first);
		for (size_t i=0; i<iter->second.size(); ++i) {
			psln(iter->second[i]->mId);
			psln(iter->second[i]->mCount);
		}
		++iter;
	}


	tmp.push_back(new Item(1, 1));
	tmp.push_back(new Item(2, 2));
	mMap[0] = tmp;

	psln("after insert 0 again");

	iter = mMap.begin();
	while (iter != mMap.end()) {
		psln("======================item===============");
		psln(iter->first);
		for (size_t i=0; i<iter->second.size(); ++i) {
			psln(iter->second[i]->mId);
			psln(iter->second[i]->mCount);
		}
		++iter;
	}

	psln("clear====================");

	iter = mMap.begin();
	while (iter != mMap.end()) {
		for (size_t i=0; i<iter->second.size(); ++i) {
			if (iter->second[i]) {
				delete iter->second[i];
				iter->second[i] = 0;
			}
		}
		psln("=========remove==========");
		++iter;
	}
}

void ELAlgorithmTest::addItemToMapOfListWithCheck( unsigned int listId, int id, int count )
{

}

void ELAlgorithmTest::removeItemWithId( unsigned int id )
{
	ItemListMap::iterator iter = mItemListsMap.find(id);
	if( iter != mItemListsMap.end())
	{
		for (size_t index=0; index<iter->second.size(); ++index) {
			if (iter->second[index]) {
				delete iter->second[index];
				iter->second[index] = 0;
			}
		}
		iter->second.clear();
		ItemList temp;
		iter->second.swap(temp);
		mItemListsMap.erase(iter);
	}
}



class Dog {

};


